using QTool.BEPUphysics.Entities;
using QTool.BEPUphysics.Entities.Prefabs;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using QTool.Inspector;
using QTool.BEPUphysics.BroadPhaseEntries.MobileCollidables;
using QTool.BEPUphysics.BroadPhaseEntries;
using QTool.BEPUphysics.NarrowPhaseSystems.Pairs;
using QTool.BEPUphysics;
using QTool.Binary;

namespace QTool.NetFrame
{
    public class QNetFrameEntity : QId
    {
        [ReadOnly]
        [ViewName("玩家ID")]
        public byte playerId;
        public Entity fixEntity { internal set; get; }
        public ISpaceObject spaceObject { internal set; get; }
        public QNetFrameEntity ParentId { internal set; get; }
        public bool ControllerEntity { internal set; get; }
        public new bool DontDestroyOnLoad { get; set; }
        public FixVector3 Position
        {
            get => fixEntity.Position;
            set
            {
                fixEntity.Position = value;
                transform.position =(Vector3) value;
                startPos = transform.position;
            }
        }
        public FixVector3 Forward
        {
            get => fixEntity.WorldTransform.Forward;
        }
        public FixQuaternion Rotation
        {
            get => fixEntity.Rotation;
            set
            {
                fixEntity.Rotation = value;
                transform.rotation = (Quaternion)value;
                startRot = transform.rotation;
            }
        }
        public FixVector3 Velocity
        {
            get => fixEntity.LinearVelocity;set => fixEntity.LinearVelocity = value;
        }
        public FixVector3 AngleVelocity
        {
            get => fixEntity.AngularVelocity; set => fixEntity.AngularVelocity = value;
        }
        public void LookAt(FixVector3 target)
        {
            fixEntity.LookAt(target);
        }
        bool _netActive = false;
        [ViewName("锁定旋转")]
        public bool freezeRoatation;
        FixQuaternion lastRotation;
        [ViewName("缓动预测")]
        public bool lerpForwards=false;
        public void SetFixActive(bool active)
        {
            FixActive = active;
            gameObject.SetActive(active);
        }
        public bool FixActive { get => _netActive;
            set
            {
                if (_netActive != value)
                {
                    if (value)
                    {
                        if (fixEntity.CollisionInformation != null)
                        {
                            if (spaceObject.Space == null)
                            {
                                FixPhysics.space.Add(spaceObject);
                            }
                        }
                    }
                    else
                    {
                        if (fixEntity.CollisionInformation != null)
                        {
                            if (spaceObject.Space != null)
                            {
                                FixPhysics.space.Remove(spaceObject);
                            }
                        }
                    }
                    _netActive = value;
                }
            }
        }
        internal FixCoroutineList FixCoroutine
        {
            get
            {
                if (_coroutine == null)
                {
                    _coroutine = new FixCoroutineList();
                }
                return _coroutine;
            }
        }
        private FixCoroutineList _coroutine;
   
        QFixBehaviour[] qNetBehaviours;
        internal void OnFixAwake()
        {
			QNetManager.NetObjList.AddCheckExist(this);
			fixCollisionInfos = GetComponents<IFixCollisionInfo>();
            qNetBehaviours = GetComponents<QFixBehaviour>();
            if (transform.parent == null)
            {
                DontDestroyOnLoad(gameObject);
            }
            foreach (var qb in qNetBehaviours)
            {
                qb.OnFixAwake();
            }
            FixPhysics.OnBeforeUpdate += BeforePhysics;
            FixPhysics.OnAfterUpdate += FreshTranform;
            FixActive = true;
            InitPhysics();
			foreach (var child in ChildList)
			{
				child.OnFixAwake();
			}
		}
        void InitPhysics()
        {
            if (fixCollisionInfos.Length > 0)
            {
                if (fixEntity is CompoundBody body)
                {
                    foreach (var c in body.CollisionInformation.Children)
                    {
                        c.CollisionInformation.Events.DetectingInitialCollision += CollisionEnter;
                        c.CollisionInformation.Events.CollisionEnded += CollisionExit;
                    }
                }
                else
                {
                    fixEntity.CollisionInformation.Events.DetectingInitialCollision += CollisionEnter;
                    fixEntity.CollisionInformation.Events.CollisionEnded += CollisionExit;
                }
            }
           
        }
		
		void RemovePhysics()
        {
            if (fixCollisionInfos.Length > 0)
            {
                if (fixEntity is CompoundBody body)
                {
                    foreach (var c in body.CollisionInformation.Children)
                    {
                        c.CollisionInformation.Events.DetectingInitialCollision -= CollisionEnter;
                        c.CollisionInformation.Events.CollisionEnded -= CollisionExit;
                    }
                }
                else
                {
                    fixEntity.CollisionInformation.Events.DetectingInitialCollision -= CollisionEnter;
                    fixEntity.CollisionInformation.Events.CollisionEnded -= CollisionExit;
                }
               
            }
        }
        internal void BeforePhysics()
        {
            if (freezeRoatation)
            {
                lastRotation = fixEntity.Rotation;
            }
        }
        internal void FreshTranform()
        {
           
            if (freezeRoatation)
            {
                fixEntity.angularVelocity = FixVector3.Zero;
                fixEntity.Rotation= lastRotation;
            }
        }
		bool startOver=false;
        internal void OnFixUpdate()
        {
			if (!startOver)
			{
				foreach (var qb in qNetBehaviours)
				{
					qb.OnFixStart();
				}
				startOver = true;
			}
			else
			{
				foreach (var qb in qNetBehaviours)
				{
					qb.OnFixUpdate();
				}
				_coroutine?.UpdateAll();
			}
            if (ParentId == null)
            {
                startPos = transform.position;
                startRot = transform.rotation;
                startTime = Time.time;
            }
        }
        Coroutine lerpCor;
        internal void OnFixDestroy()
        {
            foreach (var qb in qNetBehaviours)
            {
                qb.OnFixDestroy();
            }
            RemovePhysics();
            FixPhysics.OnBeforeUpdate -= BeforePhysics;
            FixPhysics.OnAfterUpdate -= FreshTranform;
            FixActive = false;
			foreach (var child in ChildList)
            {
				child.OnFixDestroy();
			}
			QNetManager.NetObjList.Remove(this);
		}
		protected override void OnDestroy()
		{
			base.OnDestroy();
			if (Application.isPlaying &&QNetManager.Active && QNetManager.NetObjList.Contains(this))
			{
				throw new System.Exception("QNetManager 中未删除 " + this);
			}
		}
		protected override void Awake()
        {
            base.Awake();
            fixEntity = new Entity();
            spaceObject = fixEntity;
            fixEntity.Position = transform.position;
            fixEntity.Rotation = transform.rotation;
            startPos = transform.position;
            startRot = transform.rotation;
            FreshParent();
        }
        internal List<QNetFrameEntity> ChildList = new List<QNetFrameEntity>();
        internal void FreshParent()
        {
            var newParent = transform.parent?.GetComponentInParent<QNetFrameEntity>();
            if (newParent != ParentId)
            {
                if (ParentId != null)
                {
                    ParentId.ChildList.Remove(this);
                }
                if (newParent != null)
                {
                    newParent.ChildList.AddCheckExist(this);
                }
                ParentId = newParent;
            }
        }
        protected void OnTransformParentChanged()
        {
            FreshParent();
        }
        
        Vector3 startPos;
        Quaternion startRot;
        float startTime=-1;
        private void Update()
        {
            if (ParentId == null&& startTime>=0)
            {
                var t = (Time.time - startTime) /(float) QNetManager.Instance.DelatTime;
                if (!lerpForwards&&t>1)
                {
                    t = 1;
                }
                transform.position = QLerp.LerpTo(startPos,
                (Vector3)fixEntity.Position, t);
                transform.rotation = QLerp.LerpTo(startRot,
                (Quaternion)(fixEntity.Rotation), t);
            }
        }

        IFixCollisionInfo[] fixCollisionInfos;
        public void CollisionEnter(EntityCollidable sender, Collidable other, CollidablePairHandler pair)
        {
			try
			{
				foreach (var i in fixCollisionInfos)
				{
					i.CollistionStart(sender.Tag as FixCollider, other.Tag as FixCollider);
				}
			}
			catch (System.Exception e)
			{
				Debug.LogError("碰撞开始事件出错：\n" + e);
			}
          
        }
        public void CollisionExit(EntityCollidable sender, Collidable other, CollidablePairHandler pair)
        {
			try
			{
				foreach (var i in fixCollisionInfos)
				{
					i.CollistionStop(sender.Tag as FixCollider, other.Tag as FixCollider);
				}
			}
			catch (System.Exception e)
			{
				Debug.LogError("碰撞停止事件出错：\n" + e);
			}
           
        }
        public override void Write(QBinaryWriter writer)
        {
            writer.Write(ParentId==null);
            if (ParentId == null)
            {
                writer.WriteObject(Position);
                writer.WriteObject(Rotation);
                writer.WriteObject(Velocity);
                writer.WriteObject(AngleVelocity);
            }
            base.Write(writer);
        }
		
        public override void Read(QBinaryReader reader)
        {
            if (reader.ReadBoolean())
            {
               Position= reader.ReadObject(fixEntity.Position);
               Rotation= reader.ReadObject(fixEntity.Rotation);
               Velocity= reader.ReadObject(Velocity);
               AngleVelocity = reader.ReadObject(AngleVelocity);
            }
            base.Read(reader);
        }
    }
}
